package com.packtpub.learningcypher.chapter4;

import java.util.HashMap;
import java.util.Map;
import org.neo4j.cypher.javacompat.ExecutionEngine;
import org.neo4j.cypher.javacompat.ExecutionResult;
import org.neo4j.graphdb.GraphDatabaseService;

/**
 * A set of operations to profile
 * 
 * @author Onofrio Panzarino
 */
public class Benchmark {

    private final GraphDatabaseService graphDb;
    private QueryEvaluator evaluator = new QueryEvaluator();
    
    public void setEvaluator(QueryEvaluator evaluator) {
        this.evaluator = evaluator;
    }
    
    public Benchmark(GraphDatabaseService graphDb) {
        this.graphDb = graphDb;
    }
    
    /**
     * Evaluates the finding of certain node
     */
    public void evaluateFindNode() {
        if(evaluator == null)
            evaluator = new QueryEvaluator();
        
        evaluateFindNode("user300@learningcypher.com");
        
        if(evaluator != null)
            evaluator.finish();
    }
    
    /**
     * Find a node without using parameters. This is bad for performances. 
     * Don't use it.
     * 
     * @param email
     * @deprecated
     */
    @Deprecated()
    public void evaluateFindNodeNoParameter(String email) {
        String query = "MATCH(n:User {email: '" + email + "'}) RETURN n";
        evaluate(query, null);
    }
    
    public void evaluateFindNode(String email) {
        String query = "MATCH(n:User {email: {emailQuery}}) RETURN n";
        Map<String,Object> params = new HashMap<>();
        params.put("emailQuery", email);
        
        evaluate(query, params);
    }
    
    public void evaluateFindInactiveUsers() {
        String query = "MATCH (n:User:Inactive) RETURN n";
        Map<String,Object> params = new HashMap<>();
        
        evaluate(query, params);
    }
    
    public void evaluateAvgGroupsPerUser() {
        final String query = "MATCH (user:User) -[:JOINED*]- (group:Group) \n" +
"WITH user, COUNT(group) as countG \n" +
"RETURN avg(countG)";
        evaluate(query, null);
    }
    
    public void evaluateFindInactiveUsersUsingScanHint() {
        String query = "MATCH (n:User:Inactive) USING SCAN n:Inactive RETURN n";
        Map<String,Object> params = new HashMap<>();
        
        evaluate(query, params);
    }
    
    
    
    private void evaluate(String query, Map<String,Object> params) {
        
        // NOTE: Here we recreate an engine because we want avoid caching in
        // perfomance tests!
        ExecutionEngine engine = new ExecutionEngine(graphDb);
        
        evaluator.evaluating(query);
        
        ExecutionResult result = engine.profile(query, params);
        
        evaluator.done(result);
    }
}
